package com.leyou.user.service.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.auth.inter.pojo.UserInfo;
import com.leyou.common.bean.Constant;
import com.leyou.common.bean.PageResult;
import com.leyou.common.bean.Result;
import com.leyou.common.bean.ResultCode;
import com.leyou.common.util.JsonUtils;
import com.leyou.common.util.StringUtil;
import com.leyou.user.inter.dto.PermissionPageDTO;
import com.leyou.user.inter.dto.RoleAuthorizeDTO;
import com.leyou.user.inter.pojo.Permission;
import com.leyou.user.inter.pojo.Role;
import com.leyou.user.inter.vo.AuthorizeTreeVO;
import com.leyou.user.inter.vo.MenuVO;
import com.leyou.user.service.interceptor.LoginInterceptor;
import com.leyou.user.service.mapper.PermissionMapper;
import com.leyou.user.service.mapper.RoleMapper;
import com.leyou.user.service.mapper.UserMapper;
import com.leyou.user.service.service.AuthorizeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @author zqq
 * @ClassName AuthorizeServiceImpl
 * @Description
 * @date 2020/3/24-17:51
 */
@Service
@Slf4j
public class AuthorizeServiceImpl implements AuthorizeService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Override
    public Result<List<Role>> queryRoleByUserId(Long uid) {
        List<Role> roles = null;
        try {
            roles = this.roleMapper.selectRoleByUid(uid);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(roles);
    }

    @Override
    public Result<List<Role>> queryRoleAll() {
        Role dto = new Role();
        dto.setIsDelete(false);
        List<Role> roleList = null;
        try {
            roleList = this.roleMapper.select(dto);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        for (Role role : roleList) {
            List<Permission> permissionList = this.permissionMapper.selectPermissionByCid(role.getId());
            if(permissionList.size() > 0)
                role.setList(permissionList);
        }
        return Result.newSuccess(roleList);
    }

    @Override
    public Result<List<Long>> queryPermissionByRid(Long rid) {
        List<Long> list = null;
        try {
            list = this.userSelect(rid,0L);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(list);
    }

    @Override
    public Result<List<Role>> queryRoleByAll() {
        List<Role> roleList = null;
        try {
            roleList = this.roleMapper.selectAll();
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(roleList);
    }

    @Override
    public Result updateRole(Role role) {
        if(role.getId() == null){
            role.setCreateDate(new Date());
            role.setIsDelete(false);
            try {
                this.roleMapper.insertSelective(role);
            } catch (Exception e) {
                log.error("sql异常", e);
                return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
            }
        }else{
            role.setUpdateDate(new Date());
            try {
                this.roleMapper.updateByPrimaryKeySelective(role);
            } catch (Exception e) {
                log.error("sql异常", e);
                return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
            }
        }
        return Result.newSuccess();
    }

    @Override
    @Transactional
    public Result updateRoleAuthorize(RoleAuthorizeDTO dto) {
        try {
            //删除之前的权限
            this.roleMapper.deleteRoleAndPermission(dto.getId());
            dto.getPids().forEach(pid ->{
                this.roleMapper.insertRoleAndPermission(pid,dto.getId());
            });
            //重新设置redis中的权限，如果该角色被删除，就不用更新redis
            //跟新redis
            this.updateRedisAuthorize(dto.getId(),true);

        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess();
    }

    @Override
    public Result deleteRole(Role role) {
        if(role.getIsDelete()){ //恢复
            role.setIsDelete(false);
            this.updateRedisAuthorize(role.getId(),true);
        }else{//删除
            role.setIsDelete(true);
            this.updateRedisAuthorize(role.getId(),false);
        }
        return this.updateRole(role);
    }

    @Override
    public Result<PageResult<Permission>> queryPermissionByPage(PermissionPageDTO dto) {
        Example example = new Example(Permission.class);
        Example.Criteria criteria = example.createCriteria();
        // 搜索条件
        if (StringUtil.isEmpty(dto.getKey())) {
            criteria.andLike("name", "%" + dto.getKey() + "%");
        }
        if (dto.getType() != null) {
            criteria.andEqualTo("type", dto.getType());
        }
        // 分页条件
        PageHelper.startPage(dto.getPage(), dto.getRows());

        // 添加排序
        example.setOrderByClause("sort asc");

        List<Permission> permissions = null;
        try {
            permissions = this.permissionMapper.selectByExample(example);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        PageInfo<Permission> pageInfo = new PageInfo<>(permissions);
        return Result.newSuccess(new PageResult<>(pageInfo.getTotal(),pageInfo.getPages(),permissions));
    }

    @Override
    public Result updatePermission(Permission dto) {
        if(dto.getId() == null){
            dto.setCreateDate(new Date());
            dto.setIsEnable(true);
            dto.setIsParent(false);
            try {
                this.permissionMapper.insertSelective(dto);
                if(dto.getParentId() != 0){
                    this.permissionMapper.updateByPrimaryKeySelective(new Permission(dto.getParentId(),new Date(),true));
                }
            } catch (Exception e) {
                log.error("sql异常", e);
                return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
            }
        }else{
            dto.setUpdateDate(new Date());
            try {
                this.permissionMapper.updateByPrimaryKeySelective(dto);
            } catch (Exception e) {
                log.error("sql异常", e);
                return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
            }
            //重新设置redis权限
            Result result = this.loadRedisAuthorize();
            if(!result.success()){
                return result;
            }
        }
        return Result.newSuccess();
    }

    @Override
    public Result enablePermission(Permission dto) {
        if(dto.getIsEnable()){
            dto.setIsEnable(false);
        }else{
            dto.setIsEnable(true);
        }
        return this.updatePermission(dto);
    }

    @Override
    public Result<List<AuthorizeTreeVO>> queryPermissionByTree() {
        List<AuthorizeTreeVO> voList = null;
        try {
            voList = this.selectPermission(null);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(voList);
    }

    @Override
    public Result<List<Permission>> queryPermissionByPid(Long pid) {
        Permission dto = new Permission();
        dto.setParentId(pid);
        List<Permission> list = null;
        try {
            list = this.permissionMapper.select(dto);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(list);
    }

    @Override
    public Result<Permission> queryPermissionById(Long id) {
        Permission permission = null;
        try {
            permission = this.permissionMapper.selectByPrimaryKey(id);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        return Result.newSuccess(permission);
    }

    @Override
    public Result loadRedisAuthorize() {
        Result<List<Role>> listResult = this.queryRoleAll();
        if(!listResult.success()){
            return listResult;
        }
        // 获取hash操作对象
        String key = Constant.KEY_AUTHORIZE_CODE;
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        Boolean bool = redisTemplate.hasKey(key);
        if(bool)
            redisTemplate.delete(key);
        List<Role> roleList = listResult.getData();
        Map<String,String> result = new HashMap<>();
        for (Role role : roleList) {
            result.put(role.getId().toString(), JsonUtils.serialize(role.getList()));
        }
        if(result.size() > 0){
            // 将权限数据写入redis
            hashOps.putAll(result);
        }
        return Result.newSuccess();
    }

    @Override
    public Result updateRedisAuthorize(Long rid, Boolean bool) {
        // 获取hash操作对象
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(Constant.KEY_AUTHORIZE_CODE);
        if(bool){
            hashOps.delete(rid.toString());
            List<Permission> permissionList = null;
            try {
                permissionList = this.permissionMapper.selectPermissionByCid(rid);
            } catch (Exception e) {
                log.error("sql异常", e);
                return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
            }
            // 将权限数据写入redis
            if(permissionList.size() > 0)
                hashOps.put(rid.toString(), JsonUtils.serialize(permissionList));
        }else{
            Boolean boo = hashOps.hasKey(rid.toString());
            if(boo)
                hashOps.delete(rid);
        }
        return Result.newSuccess();
    }

    @Override
    public Result<List<MenuVO>> queryMenuByUser() {
        Result<List<Permission>> listResult = this.selectMenu(0L, 1);
        if(!listResult.success())
            return Result.newFailure(listResult.getCode(),listResult.getMessage());
        List<MenuVO> vo = new ArrayList<>();
        List<Permission> permissions = listResult.getData();
        MenuVO entity = null;
        List<MenuVO> svo = null;
        for (Permission permission : permissions) {
            entity = new MenuVO(permission.getId(),permission.getIcon(),permission.getName(),permission.getUrl());
            svo = new ArrayList<>();
            MenuVO sentity = null;
            Result<List<Permission>> secondResult = this.selectMenu(permission.getId(), 2);
            for (Permission datum : secondResult.getData()) {
                sentity = new MenuVO(datum.getId(),datum.getIcon(),datum.getName(),datum.getUrl());
                svo.add(sentity);
            }
            entity.setItems(svo);
            vo.add(entity);
        }
        return Result.newSuccess(vo);
    }

    @Override
    public Result<List<Permission>> queryOtherAuthorize(String url) {
        Permission dto = new Permission();
        dto.setUrl(url);
        Permission permission = null;
        try {
            permission = this.permissionMapper.selectOne(dto);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if(permission == null){
            return Result.newFailure(ResultCode.S_SYSTEM_DATA_EXCEPTION);
        }
        return this.selectMenu(permission.getId(),3);
    }

    public Result<List<Permission>> selectMenu(Long parenId,Integer type){
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        //解析角色
        List<String> roles = JsonUtils.parseList(userInfo.getRoles(), String.class);
        List<Permission> list = null;
        try {
            list = this.permissionMapper.selectMenuByUser(String.join(",", roles), parenId, type);
        } catch (Exception e) {
            log.error("sql异常", e);
            return Result.newFailure(ResultCode.S_SYSTEM_EXCEPTION);
        }
        if(list.size() == 0)
            return Result.newSuccess(list);
        return Result.newSuccess(list);
    }

    /** 递归权限列表数据 */
    public List<AuthorizeTreeVO> selectPermission(Permission permission) throws Exception{
        if(permission == null){
            permission = new Permission();
            permission.setIsEnable(true);
            permission.setParentId(0L);
        }
        List<Permission> permissions = null;
        try {
            permissions = this.permissionMapper.select(permission);
        } catch (Exception e) {
            throw new  Exception(e);
        }
        List<AuthorizeTreeVO> voList = new ArrayList<>();
        AuthorizeTreeVO vo = null;
        if(permissions.size() > 0){
            Permission dto = new Permission();
            for (Permission per : permissions) {
                vo = new AuthorizeTreeVO();
                vo.setId(per.getId());
                vo.setName(per.getName());
                dto.setIsEnable(true);
                dto.setParentId(per.getId());
                List<AuthorizeTreeVO> children = selectPermission(dto);
                if(children.size() > 0)
                    vo.setChildren(children);
                voList.add(vo);
            }
        }
        return voList;
    }

    /** 递归查询角色对应的权限，返回叶子节点 */
    public List<Long> userSelect(Long rid, Long parentId)throws Exception{
        List<Permission> permissions = null;
        try {
            permissions = this.permissionMapper.selectPermissionBySelect(rid, parentId);
        } catch (Exception e) {
            throw new  Exception(e);
        }
        List<Long> list = new ArrayList<>();
        if(permissions.size() == 0 && parentId != 0L){
            list.add(parentId);
        }
        if(permissions.size() > 0){
            for (Permission per : permissions) {
                List<Long> longs = userSelect(rid, per.getId());
                if(longs.size() > 0){
                    list.addAll(longs);
                }
            }
        }
        return list;
    }

}
